package com.raincat.tools.nettools;

import android.annotation.SuppressLint;
import android.os.AsyncTask;
import android.os.Handler;
import android.util.Pair;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.util.Map;
import java.util.UUID;

/**
 * <pre>
 *     author : RainCat
 *     org    : Shenzhen JingYu Network Technology Co., Ltd.
 *     e-mail : nining377@gmail.com
 *     time   : 2020/03/23
 *     desc   : 上传
 *     version: 1.0
 * </pre>
 */
class ConnectUpload extends Connect {
    private static final String PREFIX = "--";
    private static final String LINE_END = "\r\n";

    private DataAsyncTask task;

    @Override
    void init(Request request) {
        super.init(request);
        if (task == null)
            task = new DataAsyncTask();
        task.executeOnExecutor(exec, request);
    }

    @SuppressLint("StaticFieldLeak")
    private class DataAsyncTask extends AsyncTask<Request, Integer, Pair<Integer, String>> {
        @Override
        protected Pair<Integer, String> doInBackground(Request... request) {
            if (isCancelled())
                return null;
            return connect(request[0]);
        }

        @Override
        protected void onPostExecute(Pair<Integer, String> result) {
            if (!getResult(result, task) && !isCancelled()) {
                Handler handler = new Handler(request.context.get().getMainLooper());
                handler.post(new Runnable() {
                    public void run() {
                        init(request);
                    }
                });
            }
        }
    }

    private Pair<Integer, String> connect(Request request) {
        String BOUNDARY = UUID.randomUUID().toString(); // 边界标识 随机生成 String PREFIX = "--" , LINE_END = "\r\n";
        String CONTENT_TYPE = "multipart/form-data"; // 内容类型
        String result;
        int errorCode = 0;

        HttpURLConnection connection = null;
        InputStream is = null;
        try {
            URL url = new URL(request.url);// 获得URL对象
            connection = (HttpURLConnection) url.openConnection();// 获得HttpURLConnection对象
            connection.setRequestMethod("POST");// 请求方式POST
            connection.setUseCaches(false);// 不使用缓存
            connection.setConnectTimeout(request.connectTimeout);// 设置超时时间
            connection.setReadTimeout(request.readTimeout);// 设置读取超时时间
            connection.setChunkedStreamingMode(0);//设置超时不自动重试
            connection.setDoInput(true);// 设置是否从httpUrlConnection读入，默认情况下是true;
            connection.setDoOutput(true);
            connection.setInstanceFollowRedirects(true);// 自动执行 http 重定向
            connection.setRequestProperty("Charset", "UTF-8");
            connection.setRequestProperty("Cookie", request.cookie);
            connection.setRequestProperty("connection", "keep-alive");
            connection.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary=" + BOUNDARY);

            OutputStream outputSteam = connection.getOutputStream();
            DataOutputStream dos = new DataOutputStream(outputSteam);
            StringBuilder sb = new StringBuilder();
            sb.append(LINE_END);
            if (request.params != null) {// 根据格式，开始拼接文本参数
                for (Map.Entry<String, Object> entry : request.params.entrySet()) {
                    sb.append(PREFIX).append(BOUNDARY).append(LINE_END);// 分界符
                    sb.append("Content-Disposition: form-data; name=\"").append(entry.getKey()).append("\"").append(LINE_END);
                    sb.append("Content-Type: text/plain; charset=utf-8" + LINE_END);
                    sb.append("Content-Transfer-Encoding: 8bit" + LINE_END);
                    sb.append(LINE_END);
                    sb.append(entry.getValue().toString());
                    sb.append(LINE_END);// 换行！
                }
            }
            dos.write(sb.toString().getBytes("utf-8"));

            if (request.filePathList != null) {
                for (int i = 0; i < request.filePathList.size(); i++) {
                    // 写入文件头请求参数
                    File file = new File(request.filePathList.get(i));
                    sb.setLength(0);
                    sb.append(PREFIX);// 开始拼接文件参数
                    sb.append(BOUNDARY);
                    sb.append(LINE_END);
                    sb.append("Content-Disposition: form-data; name=\"").append(request.fileKey).append("\"; filename=\"").append(System.currentTimeMillis()).append(file.getName()).append("\"").append(LINE_END);
                    sb.append("Content-Type: application/octet-stream; charset=utf-8" + LINE_END);
                    sb.append(LINE_END);
                    dos.write(sb.toString().getBytes("utf-8"));

                    // 写入文件数据
                    DataInputStream in = new DataInputStream(new FileInputStream(file));
                    byte[] bytes = new byte[1024];
                    int len;
                    while ((len = in.read(bytes)) != -1) {
                        dos.write(bytes, 0, len);
                    }
                    in.close();
                    dos.write(LINE_END.getBytes());// 一定还有换行
                }
                // 结束数据分隔线
                byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINE_END).getBytes();
                dos.write(end_data);
                dos.flush();
                dos.close();
            }

            // 响应码是否为200
            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK)
                is = connection.getInputStream();
            else {
                is = connection.getErrorStream();
                errorCode = connection.getResponseCode();
            }

            if (connection.getHeaderField("Set-Cookie") != null && connection.getHeaderField("Set-Cookie").length() != 0)
                saveCookie(request.context.get(), connection.getHeaderField("Set-Cookie"));
            // 获得输入流
            BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
            // 包装字节流为字符流
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            result = response.toString();
        } catch (ConnectException e) {
            errorCode = 1;
            e.printStackTrace();
            result = e.toString();
        } catch (SocketException e) {
            errorCode = 2;
            e.printStackTrace();
            result = e.getMessage();
        } catch (OutOfMemoryError e) {
            errorCode = 3;
            e.printStackTrace();
            result = e.getMessage();
        } catch (SocketTimeoutException e) {
            errorCode = 4;
            e.printStackTrace();
            result = e.getMessage();
        } catch (Exception e) {
            e.printStackTrace();
            errorCode = -1;
            result = e.getMessage();
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return new Pair<>(errorCode, result);
    }

    void cancel() {
        if (task != null && task.getStatus() == AsyncTask.Status.RUNNING)
            task.cancel(true);
    }
}
